"""
doc
"""

from typing import Iterator
from datetime import timedelta
from django.utils import timezone

from django.db import models
from app_base.models import BaseModel
from app_common import app_except


# Create your models here.
class Community(BaseModel):
    """doc"""

    community_name = models.CharField(max_length=50)
    # 物业单价, 整个系统价格最小单位为 分
    property_unit_price = models.PositiveBigIntegerField()
    # 首页
    display_url = models.CharField(max_length=255)

    class Meta:
        db_table = "Community"
        indexes = [
            models.Index(fields=["uuid"]),
            models.Index(fields=["deleted"]),
            models.Index(fields=["created_at"]),
            models.Index(fields=["community_name"]),
        ]


class House(BaseModel):
    """doc"""

    community_uuid = models.UUIDField()
    # 楼栋号
    building_num = models.CharField(max_length=20)
    # 单元号
    unit_num = models.CharField(max_length=20)
    # 门牌号
    house_num = models.CharField(max_length=20)

    # 面积大小， 平方米 m^2
    area_size = models.PositiveBigIntegerField()

    # 已缴纳的最晚日期, 此时间点 之后的， 都是未缴费，
    # 比如 2023-04-04 0.0.0， 那么 4月4日 当天是未交费的
    paid_at = models.DateTimeField()

    class Meta:
        db_table = "House"
        indexes = [
            models.Index(fields=["uuid"]),
            models.Index(fields=["deleted"]),
            models.Index(fields=["created_at"]),
            #
            models.Index(fields=["paid_at"]),
            models.Index(fields=["community_uuid"]),
            models.Index(fields=["building_num"]),
            models.Index(fields=["unit_num"]),
            models.Index(fields=["house_num"]),
            models.Index(fields=["area_size"]),
        ]


# 缴费状态


# 缴费账单
class HouseBill(BaseModel):
    """doc"""

    class BillState(models.TextChoices):
        UNPAID = "未交"
        PAID = "已缴"
        OFFLINE_PAID = "线下_已缴"

    # 缴费单，小区信息，避免级联修改，以创建账单时，属性为准
    community_uuid = models.UUIDField(null=True)

    property_unit_price = models.PositiveBigIntegerField(null=True)
    # 缴费单，房屋信息, 避免级联修改，以创建账单时，房屋属性为准
    house_uuid = models.UUIDField()
    area_size = models.PositiveBigIntegerField(null=True)

    # 账单状态
    pay_user_openid = models.CharField(default=None, max_length=50)
    state = models.CharField(
        max_length=20, choices=BillState.choices, default=BillState.UNPAID
    )

    # 房屋平方 * 小区单价 * 时长 * 折扣
    # 折扣 1-100
    discount_percent = models.PositiveBigIntegerField(default=100)
    days = models.PositiveBigIntegerField()
    # 单位是 分
    price = models.PositiveBigIntegerField(null=True)
    # 账单的缴费范围
    start_at = models.DateTimeField()
    end_at = models.DateTimeField(null=True)

    # 面积大小， 平方米 m^2

    # 账单备注

    class Meta:
        db_table = "HouseBill"
        indexes = [
            models.Index(fields=["uuid"]),
            models.Index(fields=["deleted"]),
            models.Index(fields=["created_at"]),
            #
            models.Index(fields=["community_uuid"]),
            models.Index(fields=["house_uuid"]),
            models.Index(fields=["state"]),
        ]


def _fill_house_bill(obj: HouseBill) -> HouseBill:
    # fill community_uuid
    house = House.objects.filter(deleted=False).filter(uuid=obj.house_uuid).first()
    if not house:
        raise app_except.NullErr
    obj.community_uuid = house.community_uuid
    obj.area_size = house.area_size

    # 计算账单总价格
    community = (
        Community.objects.filter(deleted=False).filter(uuid=obj.community_uuid).first()
    )
    if not community:
        raise app_except.NullErr
    obj.property_unit_price = community.property_unit_price

    obj.days = int(obj.days)
    # 单位是 分
    obj.price = int(
        int(
            int(obj.days)
            * int(obj.area_size)
            * int(obj.property_unit_price)
            * int(obj.discount_percent)
        )
        / 100.0
    )

    # 填写时间
    obj.end_at = obj.start_at + timedelta(days=obj.days)
    return obj


def batch_create_house_bill(objs: Iterator[HouseBill]) -> Iterator[HouseBill]:
    """doc"""
    _now = timezone.now()

    def _set_now(obj: HouseBill) -> HouseBill:
        obj.created_at = _now
        return obj

    _ = HouseBill.objects.bulk_create(
        objs=(_set_now(obj) for obj in objs), batch_size=1000
    )

    _objs = HouseBill.objects.filter(created_at=_now)

    HouseBill.objects.bulk_update(
        objs=(_fill_house_bill(obj) for obj in _objs),
        fields=[
            "community_uuid",
            "property_unit_price",
            "area_size",
            "price",
            "end_at",
        ],
        batch_size=1000,
    )
    _objs = HouseBill.objects.filter(created_at=_now)
    return _objs
